"""
文件下载API
处理文件下载相关的请求
"""

import os
import logging
from flask import request, jsonify, current_app, send_file, abort
from werkzeug.utils import secure_filename
from . import api_bp
from ..services.file_service import FileService
from ..services.task_service import TaskService
from ..utils.auth_utils import require_auth, get_current_user
from ..models.history import History

logger = logging.getLogger(__name__)

@api_bp.route('/download/<task_id>', methods=['GET'])
@require_auth
def download_file(task_id):
    """
    下载转换后的文件
    
    Args:
        task_id: 任务ID
        
    Returns:
        文件流或错误响应
    """
    try:
        current_user = get_current_user()
        if not current_user:
            return jsonify({'error': '用户未认证'}), 401
        
        user_id = current_user['id']
        
        # 获取任务信息
        task_service = TaskService(current_app)
        task_result = task_service.get_task_status(task_id)
        
        if not task_result['success']:
            return jsonify({'error': '任务不存在'}), 404
        
        task = task_result['task']
        
        # 检查权限
        if task['user_id'] != user_id and current_user.get('role') != 'admin':
            return jsonify({'error': '无权限下载此文件'}), 403
        
        # 检查任务状态
        if task['status'] != 'completed':
            return jsonify({'error': '任务未完成，无法下载'}), 400
        
        # 检查输出文件是否存在
        output_file_path = task.get('output_file_path')
        if not output_file_path or not os.path.exists(output_file_path):
            return jsonify({'error': '输出文件不存在'}), 404
        
        # 获取文件信息
        file_service = FileService(current_app)
        file_info_result = file_service.get_file_info(output_file_path)
        
        if not file_info_result['success']:
            return jsonify({'error': '获取文件信息失败'}), 500
        
        file_info = file_info_result['file_info']
        
        # 生成下载文件名
        original_filename = task.get('original_filename', 'document')
        output_format = task.get('output_format', 'pdf')
        
        # 移除原文件扩展名并添加新扩展名
        base_name = os.path.splitext(original_filename)[0]
        download_filename = f"{base_name}.{output_format}"
        download_filename = secure_filename(download_filename)
        
        # 记录下载历史
        try:
            History.record_download(user_id, task_id, {
                'filename': download_filename,
                'file_size': file_info['size'],
                'output_format': output_format
            })
        except Exception as e:
            logger.warning(f"记录下载历史失败: {str(e)}")
        
        # 更新任务下载次数
        try:
            task_service.update_download_count(task_id)
        except Exception as e:
            logger.warning(f"更新下载次数失败: {str(e)}")
        
        logger.info(f"文件下载: {user_id} - {task_id} - {download_filename}")
        
        # 发送文件
        return send_file(
            output_file_path,
            as_attachment=True,
            download_name=download_filename,
            mimetype=file_info.get('content_type', 'application/octet-stream')
        )
        
    except Exception as e:
        logger.error(f"文件下载失败: {str(e)}")
        return jsonify({'error': '文件下载失败'}), 500

@api_bp.route('/download/<task_id>/info', methods=['GET'])
@require_auth
def get_download_info(task_id):
    """
    获取下载信息
    
    Args:
        task_id: 任务ID
        
    Returns:
        JSON响应包含下载信息
    """
    try:
        current_user = get_current_user()
        if not current_user:
            return jsonify({'error': '用户未认证'}), 401
        
        user_id = current_user['id']
        
        # 获取任务信息
        task_service = TaskService(current_app)
        task_result = task_service.get_task_status(task_id)
        
        if not task_result['success']:
            return jsonify({'error': '任务不存在'}), 404
        
        task = task_result['task']
        
        # 检查权限
        if task['user_id'] != user_id and current_user.get('role') != 'admin':
            return jsonify({'error': '无权限访问此任务'}), 403
        
        # 检查任务状态
        if task['status'] != 'completed':
            return jsonify({'error': '任务未完成'}), 400
        
        # 检查输出文件是否存在
        output_file_path = task.get('output_file_path')
        if not output_file_path or not os.path.exists(output_file_path):
            return jsonify({'error': '输出文件不存在'}), 404
        
        # 获取文件信息
        file_service = FileService(current_app)
        file_info_result = file_service.get_file_info(output_file_path)
        
        if not file_info_result['success']:
            return jsonify({'error': '获取文件信息失败'}), 500
        
        file_info = file_info_result['file_info']
        
        # 生成下载文件名
        original_filename = task.get('original_filename', 'document')
        output_format = task.get('output_format', 'pdf')
        base_name = os.path.splitext(original_filename)[0]
        download_filename = f"{base_name}.{output_format}"
        
        download_info = {
            'task_id': task_id,
            'filename': download_filename,
            'original_filename': original_filename,
            'output_format': output_format,
            'file_size': file_info['size'],
            'file_size_mb': round(file_info['size'] / (1024 * 1024), 2),
            'content_type': file_info.get('content_type'),
            'created_at': task.get('completed_at'),
            'download_count': task.get('download_count', 0),
            'expires_at': task.get('expires_at')
        }
        
        return jsonify({
            'success': True,
            'download_info': download_info
        }), 200
        
    except Exception as e:
        logger.error(f"获取下载信息失败: {str(e)}")
        return jsonify({'error': '获取下载信息失败'}), 500

@api_bp.route('/download/<task_id>/preview', methods=['GET'])
@require_auth
def preview_file(task_id):
    """
    预览文件（仅支持HTML格式）
    
    Args:
        task_id: 任务ID
        
    Returns:
        HTML内容或错误响应
    """
    try:
        current_user = get_current_user()
        if not current_user:
            return jsonify({'error': '用户未认证'}), 401
        
        user_id = current_user['id']
        
        # 获取任务信息
        task_service = TaskService(current_app)
        task_result = task_service.get_task_status(task_id)
        
        if not task_result['success']:
            return jsonify({'error': '任务不存在'}), 404
        
        task = task_result['task']
        
        # 检查权限
        if task['user_id'] != user_id and current_user.get('role') != 'admin':
            return jsonify({'error': '无权限预览此文件'}), 403
        
        # 检查任务状态
        if task['status'] != 'completed':
            return jsonify({'error': '任务未完成，无法预览'}), 400
        
        # 检查输出格式
        if task.get('output_format') != 'html':
            return jsonify({'error': '只支持预览HTML格式文件'}), 400
        
        # 检查输出文件是否存在
        output_file_path = task.get('output_file_path')
        if not output_file_path or not os.path.exists(output_file_path):
            return jsonify({'error': '输出文件不存在'}), 404
        
        # 读取HTML内容
        try:
            with open(output_file_path, 'r', encoding='utf-8') as f:
                html_content = f.read()
        except Exception as e:
            logger.error(f"读取HTML文件失败: {str(e)}")
            return jsonify({'error': '读取文件失败'}), 500
        
        # 记录预览历史
        try:
            History.record_action(user_id, 'preview', {
                'task_id': task_id,
                'filename': task.get('original_filename'),
                'output_format': 'html'
            })
        except Exception as e:
            logger.warning(f"记录预览历史失败: {str(e)}")
        
        logger.info(f"文件预览: {user_id} - {task_id}")
        
        # 返回HTML内容
        return html_content, 200, {'Content-Type': 'text/html; charset=utf-8'}
        
    except Exception as e:
        logger.error(f"文件预览失败: {str(e)}")
        return jsonify({'error': '文件预览失败'}), 500

@api_bp.route('/download/batch', methods=['POST'])
@require_auth
def batch_download():
    """
    批量下载文件（生成ZIP压缩包）
    
    Returns:
        ZIP文件流或错误响应
    """
    try:
        current_user = get_current_user()
        if not current_user:
            return jsonify({'error': '用户未认证'}), 401
        
        user_id = current_user['id']
        
        # 获取请求数据
        data = request.get_json()
        if not data:
            return jsonify({'error': '缺少请求数据'}), 400
        
        task_ids = data.get('task_ids', [])
        
        if not task_ids:
            return jsonify({'error': '未指定任务ID'}), 400
        
        if len(task_ids) > 20:
            return jsonify({'error': '批量下载最多支持20个文件'}), 400
        
        # 验证任务并收集文件信息
        task_service = TaskService(current_app)
        files_to_zip = []
        
        for task_id in task_ids:
            # 获取任务信息
            task_result = task_service.get_task_status(task_id)
            
            if not task_result['success']:
                continue
            
            task = task_result['task']
            
            # 检查权限
            if task['user_id'] != user_id and current_user.get('role') != 'admin':
                continue
            
            # 检查任务状态和文件存在性
            if task['status'] == 'completed' and task.get('output_file_path'):
                output_file_path = task['output_file_path']
                if os.path.exists(output_file_path):
                    # 生成文件名
                    original_filename = task.get('original_filename', 'document')
                    output_format = task.get('output_format', 'pdf')
                    base_name = os.path.splitext(original_filename)[0]
                    filename = f"{base_name}.{output_format}"
                    
                    files_to_zip.append({
                        'path': output_file_path,
                        'name': secure_filename(filename),
                        'task_id': task_id
                    })
        
        if not files_to_zip:
            return jsonify({'error': '没有可下载的文件'}), 400
        
        # 创建ZIP文件
        file_service = FileService(current_app)
        zip_result = file_service.create_zip_archive(files_to_zip, user_id)
        
        if not zip_result['success']:
            return jsonify({'error': zip_result['error']}), 500
        
        zip_file_path = zip_result['zip_file_path']
        
        # 记录批量下载历史
        try:
            History.record_action(user_id, 'batch_download', {
                'task_ids': task_ids,
                'file_count': len(files_to_zip),
                'zip_size': os.path.getsize(zip_file_path)
            })
        except Exception as e:
            logger.warning(f"记录批量下载历史失败: {str(e)}")
        
        logger.info(f"批量下载: {user_id} - {len(files_to_zip)} 个文件")
        
        # 发送ZIP文件
        return send_file(
            zip_file_path,
            as_attachment=True,
            download_name=f"md2dockit_files_{len(files_to_zip)}.zip",
            mimetype='application/zip'
        )
        
    except Exception as e:
        logger.error(f"批量下载失败: {str(e)}")
        return jsonify({'error': '批量下载失败'}), 500

@api_bp.route('/download/history', methods=['GET'])
@require_auth
def get_download_history():
    """
    获取下载历史
    
    Returns:
        JSON响应包含下载历史
    """
    try:
        current_user = get_current_user()
        if not current_user:
            return jsonify({'error': '用户未认证'}), 401
        
        user_id = current_user['id']
        
        # 获取查询参数
        limit = int(request.args.get('limit', 20))
        offset = int(request.args.get('offset', 0))
        
        if limit > 100:
            limit = 100
        
        # 获取下载历史
        history_records = History.get_user_history(
            user_id, 
            action_type='download',
            limit=limit,
            offset=offset
        )
        
        return jsonify({
            'success': True,
            'history': history_records,
            'limit': limit,
            'offset': offset
        }), 200
        
    except Exception as e:
        logger.error(f"获取下载历史失败: {str(e)}")
        return jsonify({'error': '获取下载历史失败'}), 500

@api_bp.route('/download/<task_id>/url', methods=['GET'])
@require_auth
def get_download_url(task_id):
    """
    获取临时下载链接
    
    Args:
        task_id: 任务ID
        
    Returns:
        JSON响应包含临时下载链接
    """
    try:
        current_user = get_current_user()
        if not current_user:
            return jsonify({'error': '用户未认证'}), 401
        
        user_id = current_user['id']
        
        # 获取任务信息
        task_service = TaskService(current_app)
        task_result = task_service.get_task_status(task_id)
        
        if not task_result['success']:
            return jsonify({'error': '任务不存在'}), 404
        
        task = task_result['task']
        
        # 检查权限
        if task['user_id'] != user_id and current_user.get('role') != 'admin':
            return jsonify({'error': '无权限访问此任务'}), 403
        
        # 检查任务状态
        if task['status'] != 'completed':
            return jsonify({'error': '任务未完成'}), 400
        
        # 检查输出文件是否存在
        output_file_path = task.get('output_file_path')
        if not output_file_path or not os.path.exists(output_file_path):
            return jsonify({'error': '输出文件不存在'}), 404
        
        # 生成临时下载令牌
        file_service = FileService(current_app)
        token_result = file_service.generate_download_token(task_id, user_id)
        
        if not token_result['success']:
            return jsonify({'error': token_result['error']}), 500
        
        download_token = token_result['token']
        expires_at = token_result['expires_at']
        
        # 构建下载URL
        download_url = f"/api/v1/download/{task_id}/token/{download_token}"
        
        return jsonify({
            'success': True,
            'download_url': download_url,
            'token': download_token,
            'expires_at': expires_at.isoformat(),
            'expires_in_seconds': token_result['expires_in_seconds']
        }), 200
        
    except Exception as e:
        logger.error(f"获取下载链接失败: {str(e)}")
        return jsonify({'error': '获取下载链接失败'}), 500

@api_bp.route('/download/<task_id>/token/<token>', methods=['GET'])
def download_with_token(task_id, token):
    """
    使用令牌下载文件
    
    Args:
        task_id: 任务ID
        token: 下载令牌
        
    Returns:
        文件流或错误响应
    """
    try:
        # 验证下载令牌
        file_service = FileService(current_app)
        token_result = file_service.verify_download_token(task_id, token)
        
        if not token_result['success']:
            return jsonify({'error': '下载链接无效或已过期'}), 403
        
        user_id = token_result['user_id']
        
        # 获取任务信息
        task_service = TaskService(current_app)
        task_result = task_service.get_task_status(task_id)
        
        if not task_result['success']:
            return jsonify({'error': '任务不存在'}), 404
        
        task = task_result['task']
        
        # 检查输出文件是否存在
        output_file_path = task.get('output_file_path')
        if not output_file_path or not os.path.exists(output_file_path):
            return jsonify({'error': '输出文件不存在'}), 404
        
        # 获取文件信息
        file_info_result = file_service.get_file_info(output_file_path)
        
        if not file_info_result['success']:
            return jsonify({'error': '获取文件信息失败'}), 500
        
        file_info = file_info_result['file_info']
        
        # 生成下载文件名
        original_filename = task.get('original_filename', 'document')
        output_format = task.get('output_format', 'pdf')
        base_name = os.path.splitext(original_filename)[0]
        download_filename = f"{base_name}.{output_format}"
        download_filename = secure_filename(download_filename)
        
        # 记录下载历史
        try:
            History.record_download(user_id, task_id, {
                'filename': download_filename,
                'file_size': file_info['size'],
                'output_format': output_format,
                'download_method': 'token'
            })
        except Exception as e:
            logger.warning(f"记录下载历史失败: {str(e)}")
        
        # 更新任务下载次数
        try:
            task_service.update_download_count(task_id)
        except Exception as e:
            logger.warning(f"更新下载次数失败: {str(e)}")
        
        logger.info(f"令牌下载: {user_id} - {task_id} - {download_filename}")
        
        # 发送文件
        return send_file(
            output_file_path,
            as_attachment=True,
            download_name=download_filename,
            mimetype=file_info.get('content_type', 'application/octet-stream')
        )
        
    except Exception as e:
        logger.error(f"令牌下载失败: {str(e)}")
        return jsonify({'error': '下载失败'}), 500